﻿Imports System.IO

''' <summary>
''' take care of security and caching
''' </summary>
''' <remarks></remarks>
<GlobalAvalibleObject()>
Public Interface IContentDispatcher
    Inherits IContentContainer

    ''' <summary>
    ''' to be used only by perment object, object which are dispososable should register on specific content modifications
    ''' </summary>
    ''' <param name="content"></param>
    ''' <remarks></remarks>
    Event contentEdit(content As IContent)

    Function getFile(file_content As FileContent) As FileInfo

End Interface

''' <summary>
''' at this stage I want to try without cache
''' </summary>
''' <remarks></remarks>
<GlobalAvalibleObjectImplementation(implementation_of:=GetType(IContentDispatcher), overrides_exsisting:=False, singleton:=True)>
Public Class ContentMemory
    Implements IContentDispatcher

    Private _controllers As New Dictionary(Of Type, IContentSecurity)

    Private _db As IContentContainer = getGlobalObject(Of ContentsDatabase)()

    Private _cache As New Dictionary(Of Guid, IContent)

    Public Sub New()

        AddHandler _db.contentAdded, Sub(content As IContent)
                                         _cache(content.guid) = content
                                         RaiseEvent contentAdded(content)
                                     End Sub

    End Sub

    Private Sub onContentEdit(content As IContent) Handles Me.contentEdit
        _cache.Remove(content.guid)
    End Sub

    Private Sub loadSecurity(content_type As Type)
        Dim attr As ContentSecurityAttribute = getMystery().AssemblyRegister.getMysteryClassAttribute(Of ContentSecurityAttribute)(content_type)
        Dim controler As IContentSecurity
        If attr IsNot Nothing AndAlso attr.implementing_type IsNot Nothing Then
            controler = Activator.CreateInstance(attr.implementing_type)
        Else
            controler = Activator.CreateInstance(GetType(NoSecurity))
        End If
        _controllers(content_type) = controler
    End Sub

    Public Sub addContents(contents As System.Collections.Generic.IEnumerable(Of IContent)) Implements IContentContainer.addContents
        _db.addContents(contents)

        For Each item As IContent In contents
            RaiseEvent contentEdit(item)
        Next

    End Sub

    Public Event contentAdded(content As IContent) Implements IContentContainer.contentAdded

    Public Event contentChanged() Implements IContentContainer.contentChanged

    Public Event contentRemoved(content As IContent) Implements IContentContainer.contentRemoved

    Private Function SecurityFilter(content As IContent, Optional user As IUser = Nothing) As IContent
        If content Is Nothing Then Return Nothing
        Dim type As Type = content.GetType()
        If Not _controllers.ContainsKey(type) Then loadSecurity(type)
        Dim controller As IContentSecurity = _controllers(type)
        If user Is Nothing Then
            Dim ms As MysterySession = getGlobalObject(Of MysterySession)()
            user = ms.user
        End If

        If controller.canAccess(content, user) Then
            Return content
        Else
            Return Nothing
        End If
    End Function


    Private Function SecurityFilter(Of T As IContent)(contents As IEnumerable(Of T)) As IEnumerable(Of T)
        Dim type As Type = GetType(T)
        If Not _controllers.ContainsKey(type) Then loadSecurity(type)
        Dim controller As IContentSecurity = _controllers(type)
        Dim ms As MysterySession = getGlobalObject(Of MysterySession)()
        Return (From x As T In contents Select x Where controller.canAccess(x, ms.user))
    End Function

    Public Function getAll(Of T As IContent)() As System.Collections.Generic.IEnumerable(Of T) Implements IContentContainer.getAll
        Return Me.SecurityFilter(Of T)(_db.getAll(Of T))
    End Function

    Public Function getAllByFilter(Of T As IContent)(filter As T) As System.Collections.Generic.IEnumerable(Of T) Implements IContentContainer.getAllByFilter
        Return Me.SecurityFilter(Of T)(_db.getAllByFilter(Of T)(filter))
    End Function

    Public Function getAllTheContents() As System.Collections.Generic.IEnumerable(Of IContent) Implements IContentContainer.getAllTheContents
        Dim ms As MysterySession = getGlobalObject(Of MysterySession)()
        Dim user As IUser = ms.user
        Return (From x As IContent In _db.getAllTheContents() Select x Where Me.SecurityFilter(x, user) IsNot Nothing)
    End Function

    Public Function getContent(Of T As IContent)(guid As System.Guid) As T Implements IContentContainer.getContent
        Dim in_cache As Boolean = _cache.ContainsKey(guid)
        If in_cache Then Return Me.SecurityFilter(_cache(guid))
        Dim c As IContent = _db.getContent(Of T)(guid)
        _cache(guid) = c
        Return Me.SecurityFilter(c)
    End Function

    Public Sub Add(item As IContent) Implements System.Collections.Generic.ICollection(Of IContent).Add
        _db.Add(item)
        RaiseEvent contentEdit(item)
    End Sub

    Public Sub Clear() Implements System.Collections.Generic.ICollection(Of IContent).Clear
        'nothing to do here
    End Sub

    Public Function Contains(item As IContent) As Boolean Implements System.Collections.Generic.ICollection(Of IContent).Contains
        Return False
    End Function

    Public Sub CopyTo(array() As IContent, arrayIndex As Integer) Implements System.Collections.Generic.ICollection(Of IContent).CopyTo
        'nothing to do
    End Sub

    Public ReadOnly Property Count As Integer Implements System.Collections.Generic.ICollection(Of IContent).Count
        Get
            Return 0
        End Get
    End Property

    Public ReadOnly Property IsReadOnly As Boolean Implements System.Collections.Generic.ICollection(Of IContent).IsReadOnly
        Get
            Return False
        End Get
    End Property

    Public Function Remove(item As IContent) As Boolean Implements System.Collections.Generic.ICollection(Of IContent).Remove
        Dim result As Boolean = _db.Remove(item)
        getGlobalObject(Of ContentModifications).notificate(item)
        If result Then
            RaiseEvent contentChanged()
            RaiseEvent contentRemoved(item)
        End If
        Return result
    End Function

    Public Function GetEnumerator() As System.Collections.Generic.IEnumerator(Of IContent) Implements System.Collections.Generic.IEnumerable(Of IContent).GetEnumerator
        Return _db.GetEnumerator
    End Function

    Public Function GetEnumerator1() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
        Return _db.GetEnumerator
    End Function

    Public Function containsType(Of T As IContent)() As Boolean Implements IContentContainer.containsType
        Return _db.containsType(Of T)()
    End Function

    Public Event contentEdit(content As IContent) Implements IContentDispatcher.contentEdit

    Private Sub contentEditHandler(content As IContent) Handles Me.contentEdit
        getGlobalObject(Of ContentModifications).notificate(content)
    End Sub

    Public Function getLightContentRereferece(Of T As IContent)() As System.Collections.Generic.IEnumerable(Of LightContentReferece) Implements IContentContainer.getLightContentRereferece
        Return _db.getLightContentRereferece(Of T)()
    End Function

    Public Function getFile(file_content As FileContent) As System.IO.FileInfo Implements IContentDispatcher.getFile
        Dim file_root As DirectoryInfo = getGlobalObject(Of MysteryConfiguration).files_root_folder
        Return New FileInfo(Path.Combine(file_root.FullName, file_content.location.value))
    End Function

    Public Function search(search_text As String) As System.Collections.Generic.IEnumerable(Of IContent) Implements IContentContainer.search
        Return _db.search(search_text)
    End Function
End Class
